package com.zyl.blog.common.utils;

import com.zyl.blog.common.exception.BlogException;
import com.zyl.blog.common.utils.Extreme.LogUtil;
import lombok.SneakyThrows;
import org.springframework.beans.BeanUtils;
import org.springframework.util.StringUtils;

import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * @version v1.0
 * @ProjectName: Personal_Blog
 * @Package: com.zyl.common.utils
 * @ClassName: ObjectUtil
 * @Description: 对象工具类
 * @Author FinalFantasy
 * @Date 2025/2/14-13:01
 */
public class OUtil {

    private static final Pattern ANCESTOR_PATTERN = Pattern.compile("^(/\\d+)+/$");

    /**
     * 构建路径
     *
     * @param ancestors 链路
     * @param currentId 当前id
     * @return {@link String }
     */
    public static String buildPath(String ancestors, Long currentId) {
        String base = ancestors != null ? ancestors : "/";
        return base + currentId + "/";
    }

    /**
     * 构建路径
     *
     * @param original  原始路径
     * @param id        id
     * @param newStr    新字符串
     * @return {@link String }
     */
    public static String replaceIdSegment(String original, String id, String newStr) {
        // 转义id中的特殊字符，构建正则表达式
        String regex = "^.*?/" + Pattern.quote(id) + "/";
        // 替换匹配到的部分为新字符串
        return original.replaceFirst(regex, newStr);
    }

    /**
     * 父子链路构造
     *
     * @param ancestor 祖先
     * @param id 当前数据id
     * @return {@link String }
     */
    public static String AncestorBuild(String ancestor, Long id) {
        // 2. 使用字符串操作替换
        int lastSlash = ancestor.lastIndexOf('/');
        if (lastSlash == -1) {
            LogUtil.warn("设置祖先失败，祖先路径格式错误");
            throw new BlogException("父子路径格式异常");
        }

        int prevSlash = ancestor.lastIndexOf('/', lastSlash - 1);
        if (prevSlash == -1) {
            LogUtil.warn("角色设置祖先失败，祖先路径格式错误: {}", ancestor);
            throw new BlogException("父子路径格式异常");
        }

        return ancestor.substring(0, prevSlash + 1)
                + id
                + ancestor.substring(lastSlash);
    }


    /**
     * 校验路径
     *
     * @param path 路径
     */
    public static void validateAncestors(String path) {
        if (!ANCESTOR_PATTERN.matcher(path).matches()) {
            throw new BlogException("角色路径格式异常");
        }
    }


    /**
     * 将List<Map<String, Object>> 转化为泛型Map<String, <T>> 或者对象类
     * 用于基本键值映射关联到指定对象中
     * @param list 列表
     * @param key 键
     * @param clazz 值类型
     * @return Map<String, T>
     * @param <T> 泛型
     */
    public static <T> Map<String, T> listToMapObject(List<Map<String, Object>> list, String key, Class<T> clazz) {
        // 类型转换检查
        if (!clazz.isInstance(list.getFirst().get(key))) {
            LogUtil.info("类型转换错误");
            throw new RuntimeException("类型转换错误");
        }
        return list.stream()
                .collect(Collectors.toMap(
                        item -> String.valueOf(item.get(key)),
                        item -> clazz.cast(item.get(key)),
                        (existingValue, newValue) -> existingValue
                ));
    }

    /**
     * 将List<Map<String, Object>> 转化为泛型Map<String, <T>>
     * 用于拆开Map列表
     * @param list 列表
     * @param keyField 键字段
     * @param valueField 值字段
     * @return Map<String, T>
     * @param <T> 泛型
     */
    public static <T> Map<String, T> listToMap(List<Map<String, Object>> list, String keyField, String valueField, Class<T> clazz) {
        // 检查列表是否为空或为空集合
        if (list == null || list.isEmpty()) {
            return Collections.emptyMap();
        }

        // 类型转换检查
        for (Map<String, Object> item : list) {
            if (!OUtil.isNull(item.get(valueField))) {
                LogUtil.info("类型转换错误");
                throw new IllegalArgumentException("类型转换错误");
            }
        }

        // 转换并收集结果
        return list.stream()
                .collect(Collectors.toMap(
                        item -> String.valueOf(item.get(keyField)),
                        item -> clazz.cast(item.get(valueField)),
                        (existingValue, newValue) -> existingValue
                ));
    }

    /**
     * 通用Map转换方法
     * @param sourceMap 原始Map
     * @param keyMapper 键转换函数（接收原始Entry返回新Key）
     * @param valueMapper 值转换函数（接收原始Entry返回新Value）
     * @param mergeFunction 键冲突合并策略
     * @return 转换后的新Map
     */
    public static <K, V, NK, NV> Map<NK, NV> convert(
            Map<K, V> sourceMap,
            Function<Map.Entry<K, V>, NK> keyMapper,
            Function<Map.Entry<K, V>, NV> valueMapper,
            BinaryOperator<NV> mergeFunction) {

        return sourceMap.entrySet().stream()
                .collect(Collectors.toMap(
                        keyMapper,
                        valueMapper,
                        mergeFunction
                ));
    }

    /**
     * 简化版（默认覆盖策略）
     */
    public static <K, V, NK, NV> Map<NK, NV> convert(
            Map<K, V> sourceMap,
            Function<Map.Entry<K, V>, NK> keyMapper,
            Function<Map.Entry<K, V>, NV> valueMapper) {

        return convert(sourceMap, keyMapper, valueMapper, (oldVal, newVal) -> newVal);
    }

    /**
     * 保留原键的特殊场景
     */
    public static <K, V, NV> Map<K, NV> convertValues(
            Map<K, V> sourceMap,
            Function<Map.Entry<K, V>, NV> valueMapper) {

        return convert(sourceMap, Map.Entry::getKey, valueMapper);
    }

    /**
     * 复制属性到新对象（需传递目标对象）
     *
     * @param source 源对象
     * @param target 目标对象
     */
    public static void copyProperties(Object source, Object target) {
        BeanUtils.copyProperties(source, target);
    }

    /**
     * 复制属性到新对象（无需传递目标对象，自动根据类型创建）
     *
     * @param source 源对象
     * @param poType 目标对象类型
     * @return {@link T }
     */
    @SneakyThrows
    public static <T> T copyProperties(Object source, Class<T> poType) {
        if (OUtil.isNull(source)) {
            return null;
        }
        /* 通过反射机制创建目标对象 */
        T target = poType.newInstance();
        /* 从源对象中复制属性到目标对象中 */
        BeanUtils.copyProperties(source, target);
        return target;
    }

    /**
     * 忽略大小写比较两字符串内容是否相同
     *
     * @param strA 字符串A
     * @param strB 字符串B
     * @return boolean
     */
    public static boolean equalsIgnoreCase(String strA, String strB) {
        if (isNull(strA)) {
            return false;
        }
        if (strA.equals(strB)) {
            return true;
        }
        return strA.equalsIgnoreCase(strB);
    }

    /**
     * 比较两对象是否相等
     *
     * @param objA 对象A
     * @param objB 对象B
     * @return boolean
     */
    public static boolean equals(Object objA, Object objB) {
        if (objA == objB) {
            return true;
        }
        if (isNull(objA)) {
            return false;
        }
        return objA.equals(objB);
    }

    public static boolean notEquals(Object objA, Object objB) {
        return !equals(objA, objB);
    }

    /**
     * 判断某个对象是否为空指针
     *
     * @param obj 要判断的对象
     * @return boolean
     */
    public static boolean isNull(Object obj) {
        return obj == null;
    }

    /**
     * 判断某个对象是否不为空指针
     *
     * @param obj 要判断的对象
     * @return boolean
     */
    public static boolean nonNull(Object obj) {
        return !isNull(obj);
    }

    /**
     * 判断某Collection集合是否为空
     *
     * @param collection 要判断的集合对象
     * @return boolean
     */
    public static boolean isEmpty(Collection<?> collection) {
        return isNull(collection) || collection.isEmpty();
    }
    /**
     * 判断某Map集合是否为空
     *
     * @param map 要判断的集合对象
     * @return boolean
     */
    public static boolean isEmpty(Map<?, ?> map) {
        return isNull(map) || map.isEmpty();
    }

    /**
     * 判断某Collection集合是否不为空
     *
     * @param collection 要判断的集合对象
     * @return boolean
     */
    public static boolean nonEmpty(Collection<?> collection) {
        return !isEmpty(collection);
    }

    /**
     * 判断某Map集合是否不为空
     *
     * @param map 要判断的集合对象
     * @return boolean
     */
    public static boolean nonEmpty(Map<?, ?> map) {
        return !isEmpty(map);
    }

    /**
     * 判断某个字符串是否包含有效文本
     * 以下三种情况会返回false：
     * 1、值为null
     * 2、值为""
     * 3、所有字符均为空格符、回车符、换行符、制表符
     * @param s 要判断的字符串对象
     * @return boolean
     */
    public static boolean hasText(String s) {
        return StringUtils.hasText(s);
    }

    public static boolean notHasText(String s) {
        return !StringUtils.hasText(s);
    }

    /**
     * 判断多个条件是否同时满足
     *
     * @param expressions Expression
     * @return boolean
     */
    public static boolean and(boolean...expressions) {
        for (boolean expression : expressions) {
            if (!expression) {
                return false;
            }
        }
        return true;
    }

    /**
     * 判断多个条件是否满足任意一个
     *
     * @param expressions Expression
     * @return boolean
     */
    public static boolean or(boolean...expressions) {
        for (boolean expression : expressions) {
            if (expression) {
                return true;
            }
        }
        return false;
    }
}